#pragma once

using std::vector;

namespace matsu
{
#if _IPHONE_
#pragma mark mat2
#endif

	template <typename T>
	Matrix2<T>::Matrix2()
	{
		x.x = 1; x.y = 0;
		y.x = 0; y.y = 1;
	}
	template <typename T>
	Matrix2<T>::Matrix2(const T* m)
	{
		x.x = m[0]; x.y = m[1];
		y.x = m[2]; y.y = m[3];
	}

#if _IPHONE_
#pragma mark mat3
#endif

	template <typename T>
	Matrix3<T>::Matrix3()
	{
		x.x = 1; x.y = 0; x.z = 0;
		y.x = 0; y.y = 1; y.z = 0;
		z.x = 0; z.y = 0; z.z = 1;
	}
	template <typename T>
	Matrix3<T>::Matrix3(const T* m)
	{
		x.x = m[0]; x.y = m[1]; x.z = m[2];
		y.x = m[3]; y.y = m[4]; y.z = m[5];
		z.x = m[6]; z.y = m[7]; z.z = m[8];
	}
	template <typename T>
	Matrix3<T> Matrix3<T>::transposed() const
	{
		Matrix3 m;
		m.x.x = x.x; m.x.y = y.x; m.x.z = z.x;
		m.y.x = x.y; m.y.y = y.y; m.y.z = z.y;
		m.z.x = x.z; m.z.y = y.z; m.z.z = z.z;
		return m;
	}
	template <typename T>
	const T* Matrix3<T>::pointer() const
	{
		return &x.x;
	}

#if _IPHONE_
#pragma mark mat4
#endif
	template <typename T>
	Matrix4<T>::Matrix4()
	{
		x.x = 1; x.y = 0; x.z = 0; x.w = 0;
		y.x = 0; y.y = 1; y.z = 0; y.w = 0;
		z.x = 0; z.y = 0; z.z = 1; z.w = 0;
		w.x = 0; w.y = 0; w.z = 0; w.w = 1;
	}
	template <typename T>
	Matrix4<T>::Matrix4(const Matrix3<T>& m)
	{
		x.x = m.x.x; x.y = m.x.y; x.z = m.x.z; x.w = 0;
		y.x = m.y.x; y.y = m.y.y; y.z = m.y.z; y.w = 0;
		z.x = m.z.x; z.y = m.z.y; z.z = m.z.z; z.w = 0;
		w.x = 0; w.y = 0; w.z = 0; w.w = 1;
	}
	template <typename T>
	Matrix4<T>::Matrix4(const T* m)
	{
		x.x = m[0];  x.y = m[1];  x.z = m[2];  x.w = m[3];
		y.x = m[4];  y.y = m[5];  y.z = m[6];  y.w = m[7];
		z.x = m[8];  z.y = m[9];  z.z = m[10]; z.w = m[11];
		w.x = m[12]; w.y = m[13]; w.z = m[14]; w.w = m[15];
	}
	template <typename T>
	Matrix4<T> Matrix4<T>::operator * (const Matrix4& b) const
	{
		Matrix4 m;
		m.x.x = x.x * b.x.x + x.y * b.y.x + x.z * b.z.x + x.w * b.w.x;
		m.x.y = x.x * b.x.y + x.y * b.y.y + x.z * b.z.y + x.w * b.w.y;
		m.x.z = x.x * b.x.z + x.y * b.y.z + x.z * b.z.z + x.w * b.w.z;
		m.x.w = x.x * b.x.w + x.y * b.y.w + x.z * b.z.w + x.w * b.w.w;
		m.y.x = y.x * b.x.x + y.y * b.y.x + y.z * b.z.x + y.w * b.w.x;
		m.y.y = y.x * b.x.y + y.y * b.y.y + y.z * b.z.y + y.w * b.w.y;
		m.y.z = y.x * b.x.z + y.y * b.y.z + y.z * b.z.z + y.w * b.w.z;
		m.y.w = y.x * b.x.w + y.y * b.y.w + y.z * b.z.w + y.w * b.w.w;
		m.z.x = z.x * b.x.x + z.y * b.y.x + z.z * b.z.x + z.w * b.w.x;
		m.z.y = z.x * b.x.y + z.y * b.y.y + z.z * b.z.y + z.w * b.w.y;
		m.z.z = z.x * b.x.z + z.y * b.y.z + z.z * b.z.z + z.w * b.w.z;
		m.z.w = z.x * b.x.w + z.y * b.y.w + z.z * b.z.w + z.w * b.w.w;
		m.w.x = w.x * b.x.x + w.y * b.y.x + w.z * b.z.x + w.w * b.w.x;
		m.w.y = w.x * b.x.y + w.y * b.y.y + w.z * b.z.y + w.w * b.w.y;
		m.w.z = w.x * b.x.z + w.y * b.y.z + w.z * b.z.z + w.w * b.w.z;
		m.w.w = w.x * b.x.w + w.y * b.y.w + w.z * b.z.w + w.w * b.w.w;
		return m;
	}
	template <typename T>
	Matrix4<T>& Matrix4<T>::operator *= (const Matrix4& b)
	{
		Matrix4 m = *this * b;
		return (*this = m);
	}
	template <typename T>
	Vector4<T> Matrix4<T>::operator *(const Vector4<T> &b) const
	{
		Vector4<T> v;
		v.x = x.x*b.x + x.y*b.y + x.z*b.z + x.w*b.w;
		v.y = y.x*b.x + y.y*b.y + y.z*b.z + y.w*b.w;
		v.z = z.x*b.x + z.y*b.y + z.z*b.z + z.w*b.w;
		v.w = w.x*b.x + w.y*b.y + w.z*b.z + w.w*b.w;
		return v;
	}
	template <typename T>
	Vector4<T> Matrix4<T>::multi(const Vector4<T> &b) const
	{
		//operator *와는 곱셈 방향이 좀 다름
		Vector4<T> v;
		v.x = x.x*b.x + y.x*b.y + z.x*b.z + w.x*b.w;
		v.y = x.y*b.x + y.y*b.y + z.y*b.z + w.y*b.w;
		v.z = x.z*b.x + y.z*b.y + z.z*b.z + w.z*b.w;
		v.w = x.w*b.x + y.w*b.y + z.w*b.z + w.w*b.w;
		return v;
	}

	template <typename T>
	Matrix4<T> Matrix4<T>::transposed() const
	{
		Matrix4 m;
		m.x.x = x.x; m.x.y = y.x; m.x.z = z.x; m.x.w = w.x;
		m.y.x = x.y; m.y.y = y.y; m.y.z = z.y; m.y.w = w.y;
		m.z.x = x.z; m.z.y = y.z; m.z.z = z.z; m.z.w = w.z;
		m.w.x = x.w; m.w.y = y.w; m.w.z = z.w; m.w.w = w.w;
		return m;
	}
	template <typename T>
	Matrix3<T> Matrix4<T>::toMat3() const
	{
		Matrix3<T> m;
		m.x.x = x.x; m.y.x = y.x; m.z.x = z.x;
		m.x.y = x.y; m.y.y = y.y; m.z.y = z.y;
		m.x.z = x.z; m.y.z = y.z; m.z.z = z.z;
		return m;
	}
	template <typename T>
	const T* Matrix4<T>::pointer() const
	{
		return &x.x;
	}
	template <typename T>
	Matrix4<T> Matrix4<T>::identity()
	{
		return Matrix4();
	}
}
